package com.hup.minicontroller.server.screenImageService;

import android.app.Activity;
import android.content.Context;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.projection.MediaProjection;
import android.util.Log;
import android.view.Display;
import android.view.Surface;

import com.hup.minicontroller.common.framework.SubThreadHandler;
import com.hup.minicontroller.common.util.DisplayUtil;
import com.hup.minicontroller.server.ServerApplication;
import com.hup.minicontroller.server.activity.MainActivity;
import com.hup.minicontroller.server.androidService.AppService;
import com.hup.minicontroller.server.auth.MediaProjectionAuthForSIS;
import com.hup.minicontroller.server.model.ControlConfig;
import com.hup.minicontroller.server.mvp.IMainView;
import com.hup.minicontroller.server.mvp.IScreenImageService;
import com.hup.minicontroller.server.mvp.IServerHandler.ServerHandlerList;
import com.hup.minicontroller.server.service.MainService;

/**
 * 基于 {@link MediaProjection}的获取屏幕图像的服务;
 * .权限:每次启动录屏时都需要用Activity申请,用户在界面上确认,某些系统会有"下次一定"的按钮
 * .需要依赖安卓前台服务 {@link AppService}
 * .图像数据是在屏幕变化后才才产生的,不是线程轮询方式
 * .关于开关服务的模式: {@link MainService#SWITCH_SCREEN_ON_BOOT}
 */
public class MediaProjectionScreenService implements IScreenImageService {
    private static final String TAG = MediaProjectionScreenService.class.getSimpleName();

    private State state = State.STOPPED;
    private final ServerHandlerList serverHandlers;
    private final ControlConfig controlConfig;

    private MediaProjection mediaProjection;
    private VirtualDisplay virtualDisplay;
    private IScreenDataProcessor screenDataProcessor;

    public MediaProjectionScreenService() {
        serverHandlers = ServerApplication.getBean(ServerHandlerList.class);
        controlConfig = ServerApplication.getBean(MainService.class).getAppState().getControlConfig();
    }

    private void setState(State state) {
        Log.i(TAG, "setState: " + this.state + "->" + state);
        this.state = state;
        if (state != State.STARTING) {
            boolean enable = state == State.STARTED;
            controlConfig.setCanEnableScreen(enable);
            if (!enable) controlConfig.setEnableScreen(false);
            ServerApplication.executeIfExist(IMainView.class, IMainView::onControlConfigChanged);
            ServerApplication.getBean(SubThreadHandler.class).post(serverHandlers::onControlConfigChanged);
        }
    }

    @Override
    public void switchService(boolean isStart) {
        Log.i(TAG, "switchService: isStart=" + isStart + ", state=" + state);
        if (isStart && state == State.STOPPED) {
            setState(State.STARTING);
            acquireMediaProjection();
            //else 启动中,已启动时:直接return
        } else if (!isStart && state != State.STOPPED) {
            //启动中,已启动时:都可以直接关闭
            stopCapture();
        }
    }

    /**
     * 使用Activity请求录屏权限
     *
     * @apiNote mediaProjection.createVirtualDisplay时, 必须每次都要申请权限,
     * 目前开发机上没有[下次一定]的按钮, 所以每次都要用户确认权限
     */
    private void acquireMediaProjection() {
        IMainView mainView = ServerApplication.getBeanNullable(IMainView.class);
        if (mainView == null) {
            Log.i(TAG, "acquireMediaProjection: 没有启动Activity");
            MainActivity.startAndAcquireMediaProjection();
        } else {
            MediaProjectionAuthForSIS.acquireMediaProjectionForService((Activity) mainView);
        }
    }

    /**
     * 调用 {@link MediaProjectionAuthForSIS#acquireMediaProjectionForService(Activity)} 后的结果回调
     *
     * @param mediaProjection nullable
     */
    @Override
    public void acquireMediaProjectionResult(MediaProjection mediaProjection) {
        Log.i(TAG, "acquireMediaProjectionResult: " + mediaProjection);
        if (mediaProjection == null) {
            Log.e(TAG, "acquireMediaProjectionResult: mediaProjection == null");
            setState(State.STOPPED);
            return;
        }
        if (state == State.STOPPED) {
            /*
            骚操作:
            .权限弹窗时,用户在系统页面结束掉 APPServer
            .权限弹窗时,点了确认,又马上退出app(人类是没这么快的)
             */
            Log.i(TAG, "acquireMediaProjectionResult: 通过权限后,但其他操作已停止模块启动");
            return;
        }
        this.mediaProjection = mediaProjection;
        startCapture();
    }

    private void startCapture() {
        Context context = ServerApplication.getContext();
        Display display = DisplayUtil.getDisplay(context);
        if (display == null) {
            Log.e(TAG, "acquireMediaProjectionResult: context.getDisplay()==null??");
            return;
        }
        Point screenSize = new Point();
        display.getRealSize(screenSize);//受旋转状态的影响
        int rotation = display.getRotation();//不受旋转状态的影响
        if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
            //要修正分辨率,避免影响Processor的旋转处理
            int temp = screenSize.x;
            //noinspection SuspiciousNameCombination
            screenSize.x = screenSize.y;
            screenSize.y = temp;
        }
        Log.i(TAG, "startCapture: screenSize=" + screenSize + ", rotation=" + rotation);
        //使用不同的处理器处理录屏图像,按需修改getProcessorType方法
        Class<? extends IScreenDataProcessor> processorType = getProcessorType();
        if (processorType == ImageReaderProcessor.class) {
            screenDataProcessor = new ImageReaderProcessor(screenSize);
        } else if (processorType == SurfaceViewProcessor.class) {
            screenDataProcessor = new SurfaceViewProcessor(screenSize);
        } else if (processorType == MediaCodecProcessor.class) {
            screenDataProcessor = new MediaCodecProcessor(screenSize);
        }
        /*
        设置IServerHandler回调,发送屏幕数据;
        由screenDataProcessor处理的内容:
        .图像配置:是否传输图像,帧率,图像大小,图像质量...
        .线程:使用SubHandlerThread调用回调
         */
        screenDataProcessor.setScreenDataCallback(serverHandlers::doSendScreenData);
        Surface surface = screenDataProcessor.getSurface();
        if (surface == null) {
            Log.e(TAG, "startCapture: surface==null, screenDataProcessor" + screenDataProcessor.getClass().getSimpleName());
            screenDataProcessor = null;
            mediaProjection = null;
            setState(State.STOPPED);
            return;
        }
        //开始录屏
        virtualDisplay = mediaProjection.createVirtualDisplay(getClass().getSimpleName(),
                screenSize.x, screenSize.y, 1,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                surface,
                null, null);
        setState(State.STARTED);
    }

    private void stopCapture() {
        Log.i(TAG, "stopCapture: ");
        setState(State.STOPPED);
        /*
        对象为空的情况:
        用户没有骚操作:申请权限时,关闭服务,则对象是不会空的
         */
        if (virtualDisplay != null) {
            virtualDisplay.release();
            virtualDisplay = null;
        }
        if (mediaProjection != null) {
            mediaProjection.stop();
            mediaProjection = null;
        }
        if (screenDataProcessor != null) {
            screenDataProcessor.release();
            screenDataProcessor = null;
        }
    }

    private enum State {
        STARTED, STOPPED, STARTING
    }

}
